home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Pascal / Libraries / WASTE 1.1a4 / WASTE Source / WEScraps.p < prev    next >
Encoding:
Text File  |  1994-11-10  |  12.9 KB  |  488 lines  |  [TEXT/PJMM]

  1. unit WEScraps;
  2.  
  3. { WASTE PROJECT: }
  4. { Routines for manipulating style scraps and object soups }
  5.  
  6. { Copyright © 1993-1994 Marco Piovanelli }
  7. { All Rights Reserved }
  8.  
  9. interface
  10.     uses
  11.         WEDrawing;
  12.  
  13.     function _WEPrependStyle (hStyleScrap: Handle;
  14.                                     var info: WERunInfo;
  15.                                     offsetDelta: LongInt): OSErr;
  16.     function _WEAppendStyle (hStyleScrap: Handle;
  17.                                     var info: WERunInfo;
  18.                                     offset: LongInt): OSErr;
  19.     function _WEPrependObject (hSoup: Handle;
  20.                                     var info: WERunInfo;
  21.                                     offsetDelta: LongInt): OSErr;
  22.     function _WEAppendObject (hSoup: Handle;
  23.                                     var info: WERunInfo;
  24.                                     offset: LongInt): OSErr;
  25.     function WECopyRange (rangeStart, rangeEnd: LongInt;
  26.                                     hText, hStyles, hSoup: Handle;
  27.                                     hWE: WEHandle): OSErr;
  28.     function WECopy (hWE: WEHandle): OSErr;
  29.  
  30. implementation
  31.     uses
  32.         AppleEvents;
  33.  
  34.     function _WEPrependStyle (hStyleScrap: Handle;
  35.                                     var info: WERunInfo;
  36.                                     offsetDelta: LongInt): OSErr;
  37.  
  38. { compare the stylistic attributes in info with the first element of the specified }
  39. { style scrap: if they differ, prepend a new element to the style scrap. }
  40. { in any case, advance all character offsets in the style scrap by offsetDelta }
  41.  
  42.         label
  43.             1;
  44.         var
  45.             pScrap: TEStyleScrapPtr;
  46.             scrapSize: Size;
  47.             i: Integer;
  48.             err: OSErr;
  49.     begin
  50.         pScrap := TEStyleScrapHandle(hStyleScrap)^;
  51.         if (_WEBlockCmp(@pScrap^.scrpStyleTab[0].scrpTEAttrs, @info.runAttrs.runTEAttrs, SizeOf(info.runAttrs.runTEAttrs)) = false) then
  52.             begin
  53.  
  54. { lengthen the style scrap }
  55.                 scrapSize := %_GetHandleSize(hStyleScrap);
  56.                 err := %_SetHandleSize(hStyleScrap, scrapSize + SizeOf(TEStyleScrapElement));
  57.                 if (err <> noErr) then
  58.                     goto 1;
  59.  
  60. { move old contents forward }
  61.                 pScrap := TEStyleScrapHandle(hStyleScrap)^;
  62.                 %_BlockMoveData(@pScrap^.scrpStyleTab[0], @pScrap^.scrpStyleTab[1], scrapSize - SizeOf(pScrap^.scrpNStyles));
  63.  
  64. { insert a new element at the beginning }
  65.                 pScrap^.scrpStyleTab[0].scrpStartChar := 0;
  66.                 pScrap^.scrpStyleTab[0].scrpTEAttrs := info.runAttrs.runTEAttrs;
  67.  
  68. { increment scrap counter }
  69.                 pScrap^.scrpNStyles := pScrap^.scrpNStyles + 1;
  70.  
  71.             end;  { if not _WEBlockCmp }
  72.  
  73. { update char offsets within the style scrap }
  74.         for i := pScrap^.scrpNStyles - 1 downto 1 do
  75.             with pScrap^.scrpStyleTab[i] do
  76.                 scrpStartChar := scrpStartChar + offsetDelta;
  77.  
  78. { clear result code }
  79.         err := noErr;
  80.  
  81. 1:
  82. { return result code }
  83.         _WEPrependStyle := err;
  84.  
  85.     end;  { _WEPrependStyle }
  86.  
  87.     function _WEAppendStyle (hStyleScrap: Handle;
  88.                                     var info: WERunInfo;
  89.                                     offset: LongInt): OSErr;
  90.  
  91. { compare the stylistic attributes in info with the last element of the specified }
  92. { style scrap: if they differ, append a new element to the style scrap. }
  93.  
  94.         label
  95.             1;
  96.         var
  97.             pScrap: TEStyleScrapPtr;
  98.             element: TEStyleScrapElement;
  99.             err: OSErr;
  100.     begin
  101.         pScrap := TEStyleScrapHandle(hStyleScrap)^;
  102.         if (_WEBlockCmp(@pScrap^.scrpStyleTab[pScrap^.scrpNStyles - 1].scrpTEAttrs, @info.runAttrs.runTEAttrs, SizeOf(info.runAttrs.runTEAttrs)) = false) then
  103.             begin
  104.  
  105. { create a new style scrap element }
  106.                 element.scrpStartChar := offset;
  107.                 element.scrpTEAttrs := info.runAttrs.runTEAttrs;
  108.  
  109. { append it at the end of the style scrap }
  110.                 err := %_PtrAndHand(@element, hStyleScrap, SizeOf(element));
  111.                 if (err <> noErr) then
  112.                     goto 1;
  113.  
  114. { increment scrap counter }
  115.                 pScrap := TEStyleScrapHandle(hStyleScrap)^;
  116.                 pScrap^.scrpNStyles := pScrap^.scrpNStyles + 1;
  117.  
  118.             end;  { if not _WEBlockCmp }
  119.  
  120. { clear result code }
  121.         err := noErr;
  122.  
  123. 1:
  124. { return result code }
  125.         _WEAppendStyle := err;
  126.  
  127.     end;  { _WEAppendStyle }
  128.  
  129.     function _WEPrependObject (hSoup: Handle;
  130.                                     var info: WERunInfo;
  131.                                     offsetDelta: LongInt): OSErr;
  132.  
  133. { if info describes an embedded object, prepend a new object descriptor, }
  134. { complete with the associated object data, to the specified soup. }
  135. { in any case, advance all character offsets in the soup by offsetDelta }
  136.  
  137.         label
  138.             1;
  139.         var
  140.             pDesc: WEObjectDescPtr;
  141.             pSoup: WESoupPtr;
  142.             soupSize, objectDataSize, extraSize: Size;
  143.             i: Integer;
  144.             err: OSErr;
  145.     begin
  146.  
  147. { get size of existing soup }
  148.         soupSize := %_GetHandleSize(hSoup);
  149.  
  150. { extract object descriptor handle from WERunInfo record }
  151. { if hObject is non-NIL, info describes an embedded object }
  152.         if (info.runAttrs.runStyle.tsObject <> kNullObject) then
  153.             begin
  154.                 pDesc := WEObjectDescHandle(info.runAttrs.runStyle.tsObject)^;
  155.  
  156. { get size of object data }
  157.                 objectDataSize := %_GetHandleSize(pDesc^.objectDataHandle);
  158.  
  159. { extra size to add to existing soup is descriptor size + object data size }
  160.                 extraSize := SizeOf(WESoup) + objectDataSize;
  161.  
  162. { resize the soup }
  163.                 err := %_SetHandleSize(hSoup, soupSize + extraSize);
  164.                 if (err <> noErr) then
  165.                     goto 1;
  166.  
  167. { move old contents forward }
  168.                 pSoup := WESoupHandle(hSoup)^;
  169.                 %_BlockMoveData(Ptr(pSoup), Ptr(LongInt(pSoup) + extraSize), soupSize);
  170.  
  171. { insert the new object descriptor at the beginning }
  172.                 _WEBlockClr(Ptr(pSoup), SizeOf(WESoup));
  173.                 pDesc := WEObjectDescHandle(info.runAttrs.runStyle.tsObject)^;
  174.                 pSoup^.soupType := pDesc^.objectType;
  175.                 pSoup^.soupSize := pDesc^.objectSize;
  176.                 pSoup^.soupDataSize := objectDataSize;
  177.  
  178. { then copy the object data }
  179.                 %_BlockMoveData(pDesc^.objectDataHandle^, Ptr(LongInt(pSoup) + SizeOf(WESoup)), objectDataSize);
  180.  
  181.             end
  182.         else
  183.             begin
  184.                 pSoup := WESoupHandle(hSoup)^;
  185.                 extraSize := 0;
  186.             end;
  187.  
  188. { update char offsets within the soup }
  189.         while (soupSize > 0) do
  190.             begin
  191.                 pSoup := WESoupPtr(LongInt(pSoup) + extraSize);
  192.                 pSoup^.soupOffset := pSoup^.soupOffset + offsetDelta;
  193.                 extraSize := pSoup^.soupDataSize + SizeOf(WESoup);
  194.                 soupSize := soupSize - extraSize;
  195.             end;
  196.  
  197. { clear result code }
  198.         err := noErr;
  199.  
  200. 1:
  201. { return result code }
  202.         _WEPrependObject := err;
  203.  
  204.     end;  { _WEPrependObject }
  205.  
  206.     function _WEAppendObject (hSoup: Handle;
  207.                                     var info: WERunInfo;
  208.                                     offset: LongInt): OSErr;
  209.  
  210. { if info describes an embedded object, append a new object descriptor, }
  211. { complete with the associated object data, to the specified soup. }
  212.  
  213.         label
  214.             1;
  215.         var
  216.             pDesc: WEObjectDescPtr;
  217.             hObjectData: Handle;
  218.             soupItem: WESoup;
  219.             saveDataLock: Boolean;
  220.             err: OSErr;
  221.     begin
  222.         if (info.runAttrs.runStyle.tsObject <> kNullObject) then
  223.             begin
  224.                 pDesc := WEObjectDescHandle(info.runAttrs.runStyle.tsObject)^;
  225.                 hObjectData := pDesc^.objectDataHandle;
  226.  
  227. { fill in a soup item }
  228.                 _WEBlockClr(@soupItem, SizeOf(soupItem));
  229.                 soupItem.soupOffset := offset;
  230.                 soupItem.soupType := pDesc^.objectType;
  231.                 soupItem.soupSize := pDesc^.objectSize;
  232.                 soupItem.soupDataSize := %_GetHandleSize(hObjectData);
  233.  
  234. { append it to the soup handle }
  235.                 err := %_PtrAndHand(@soupItem, hSoup, SizeOf(soupItem));
  236.                 if (err <> noErr) then
  237.                     goto 1;
  238.  
  239. { append the actual object data to the soup handle }
  240.                 saveDataLock := _WESetHandleLock(hObjectData, true);
  241.                 err := %_PtrAndHand(hObjectData^, hSoup, soupItem.soupDataSize);
  242.                 IgnoreBoolean(_WESetHandleLock(hObjectData, saveDataLock));
  243.                 if (err <> noErr) then
  244.                     goto 1;
  245.  
  246.             end;  { if object reference is not NIL }
  247.  
  248. { clear result code }
  249.         err := noErr;
  250.  
  251. 1:
  252. { return result code }
  253.         _WEAppendObject := err;
  254.  
  255.     end;  { _WEAppendObject }
  256.  
  257.     function WECopyRange (rangeStart, rangeEnd: LongInt;
  258.                                     hText, hStyles, hSoup: Handle;
  259.                                     hWE: WEHandle): OSErr;
  260.  
  261. { Make a copy of the specified range of text: store the characters in hText }
  262. { and the associated style scrap in hStyles.  The handles are resized as necessary. }
  263. { Specify NIL in hText or hStyles if you don't want the corresponding info returned. }
  264.  
  265.         label
  266.             1;
  267.         var
  268.             pWE: WEPtr;
  269.             rangeLength: LongInt;
  270.             firstRun, nRuns, i: LongInt;
  271.             startChar: LongInt;
  272.             info: WERunInfo;
  273.             pElement: Ptr;
  274.             pDesc: WEObjectDescPtr;
  275.             saveWELock: Boolean;
  276.             err: OSErr;
  277.     begin
  278.  
  279. { lock the WE record }
  280.         saveWELock := _WESetHandleLock(hWE, true);
  281.         pWE := hWE^;
  282.  
  283. { range-check parameters and reorder them if necessary }
  284.         rangeStart := _WEPinInRange(rangeStart, 0, pWE^.textLength);
  285.         rangeEnd := _WEPinInRange(rangeEnd, 0, pWE^.textLength);
  286.         _WEReorder(rangeStart, rangeEnd);
  287.         rangeLength := rangeEnd - rangeStart;
  288.  
  289.         if (hText <> nil) then
  290.             begin
  291.  
  292. { resize the given handle }
  293.                 err := %_SetHandleSize(hText, rangeLength);
  294.                 if (err <> noErr) then
  295.                     goto 1;
  296.  
  297. { copy the text range }
  298.                 %_BlockMoveData(Ptr(LongInt(pWE^.hText^) + rangeStart), hText^, rangeLength);
  299.  
  300.             end;  { if (hText <> NIL) }
  301.  
  302. { make the soup handle zero-length }
  303.         if (hSoup <> nil) then
  304.             begin
  305.                 err := %_SetHandleSize(hSoup, 0);
  306.                 if (err <> noErr) then
  307.                     goto 1;
  308.             end;
  309.  
  310.         if (hStyles <> nil) or (hSoup <> nil) then
  311.             begin
  312.  
  313. { count how many style runs there are in the selection range }
  314.                 firstRun := _WEOffsetToRun(rangeStart, hWE);
  315.                 nRuns := _WEOffsetToRun(rangeEnd - 1, hWE) - firstRun + 1;
  316.  
  317.                 if (hStyles <> nil) then
  318.                     begin
  319.  
  320. { resize the given style scrap handle and lock it in high heap }
  321.                         err := %_SetHandleSize(hStyles, %_LongMul(0, nRuns, SizeOf(ScrpSTElement)) + 2);
  322.                         if (err <> noErr) then
  323.                             goto 1;
  324.                         HLockHi(hStyles);
  325.                         pElement := hStyles^;
  326.  
  327. { fill in the style count in the style scrap }
  328. { *** POTENTIAL PROBLEM: if nRuns > 32767, scrpNStyles will be invalid *** }
  329.                         IntegerPtr(pElement)^ := nRuns;
  330.                         pElement := Ptr(LongInt(pElement) + SizeOf(Integer));
  331.  
  332.                     end;  { if hStyles <> NIL }
  333.  
  334. { loop through every style run in the selection range }
  335.                 for i := 0 to nRuns - 1 do
  336.                     begin
  337.                         _WEGetIndStyle(firstRun + i, info, hWE);
  338.  
  339. { calculate the start character for this style run, relative to the beginning of the range }
  340.                         startChar := info.runStart - rangeStart;
  341.                         if (startChar < 0) then
  342.                             begin
  343.                                 startChar := 0;
  344.                                 info.runAttrs.runStyle.tsObject := kNullObject;
  345.                             end;
  346.  
  347. { fill in an item in the style scrap }
  348.                         if (hStyles <> nil) then
  349.                             begin
  350.                                 info.runAttrs.runStyle.tsFlags := 0;        { don't export internal flags }
  351.                                 TEStyleScrapElementPtr(pElement)^.scrpStartChar := startChar;
  352.                                 TEStyleScrapElementPtr(pElement)^.scrpTEAttrs := info.runAttrs.runTEAttrs;
  353.                                 pElement := Ptr(LongInt(pElement) + SizeOf(TEStyleScrapElement));
  354.                             end;
  355.  
  356.                         if (hSoup <> nil) then
  357.                             begin
  358.  
  359. { if this style run references an embedded object, append it to the "soup" }
  360.                                 err := _WEAppendObject(hSoup, info, startChar);
  361.                                 if (err <> noErr) then
  362.                                     goto 1;
  363.                             end;
  364.  
  365.                     end;  { for }
  366.             end;
  367.  
  368. { clear result code }
  369.         err := noErr;
  370.  
  371. 1:
  372. { return result code }
  373.         WECopyRange := err;
  374.  
  375. { unlock the style scrap handle }
  376.         if (hStyles <> nil) then
  377.             HUnlock(hStyles);
  378.  
  379. { unlock the WE record }
  380.         IgnoreBoolean(_WESetHandleLock(hWE, saveWELock));
  381.  
  382.     end;  { WECopyRange }
  383.  
  384.     function WECopy (hWE: WEHandle): OSErr;
  385.  
  386. { Copy the selection range to the desk scrap }
  387.  
  388.         label
  389.             0, 1;
  390.         type
  391.             AEDescPtr = ^AEDesc;
  392.             AEDescHandle = ^AEDescPtr;
  393.         var
  394.             pWE: WEPtr;
  395.             d: array[0..2] of AEDesc;
  396.             hObjectDesc: WEObjectDescHandle;
  397.             i, numTypes: Integer;
  398.             hItem: Handle;
  399.             itemSize: Size;
  400.             disposeData: Boolean;
  401.             saveDataLock, saveWELock: Boolean;
  402.             err: OSErr;
  403.     begin
  404.         d[0].dataHandle := nil;
  405.         d[1].dataHandle := nil;
  406.         d[2].dataHandle := nil;
  407.         disposeData := false;
  408.  
  409. { lock the WE record }
  410.         saveWELock := _WESetHandleLock(hWE, true);
  411.         pWE := hWE^;
  412.  
  413. { do nothing if the selection range is empty }
  414.         if (pWE^.selStart = pWE^.selEnd) then
  415.             goto 0;
  416.  
  417. { clear the desk scrap }
  418.         err := ZeroScrap;
  419.         if (err <> noErr) then
  420.             goto 1;
  421.  
  422. { if the selection range consists of an embedded object, copy that }
  423.         if (WEGetSelectedObject(hObjectDesc, hWE) = noErr) then
  424.             begin
  425.                 d[0] := AEDescHandle(hObjectDesc)^^;
  426.                 numTypes := 1;
  427.             end
  428.         else
  429.             begin
  430.  
  431. { allocate three zero-length handles to hold the text, the styles and the "soup" }
  432.                 for i := 0 to 2 do
  433.                     begin
  434.                         err := _WEAllocate(0, kAllocTemp, d[i].dataHandle);
  435.                         if (err <> noErr) then
  436.                             goto 1;
  437.                     end;  { for }
  438.  
  439. { make a copy of the selection text, styles and soup }
  440.                 err := WECopyRange(pWE^.selStart, pWE^.selEnd, d[0].dataHandle, d[1].dataHandle, d[2].dataHandle, hWE);
  441.                 if (err <> noErr) then
  442.                     goto 1;
  443.  
  444. { tag the data }
  445.                 d[0].descriptorType := kTypeText;
  446.                 d[1].descriptorType := kTypeStyles;
  447.                 d[2].descriptorType := kTypeSoup;
  448.                 numTypes := 3;
  449.                 disposeData := true;
  450.             end;
  451.  
  452. { copy the items to the desk scrap }
  453.         for i := 0 to numTypes - 1 do
  454.             begin
  455.                 hItem := d[i].dataHandle;
  456.                 itemSize := %_GetHandleSize(hItem);
  457.                 if (itemSize > 0) then
  458.                     begin
  459.                         saveDataLock := _WESetHandleLock(hItem, true);
  460.                         err := PutScrap(itemSize, d[i].descriptorType, hItem^);
  461.                         IgnoreBoolean(_WESetHandleLock(hItem, saveDataLock));
  462.                         if (err <> noErr) then
  463.                             goto 1;
  464.                     end;
  465.             end;  { for }
  466.  
  467. 0:
  468. { clear result code }
  469.         err := noErr;
  470.  
  471. 1:
  472. { return result code }
  473.         WECopy := err;
  474.  
  475. { clean up }
  476.         if (disposeData) then
  477.             begin
  478.                 _WEForgetHandle(d[0].dataHandle);
  479.                 _WEForgetHandle(d[1].dataHandle);
  480.                 _WEForgetHandle(d[2].dataHandle);
  481.             end;
  482.  
  483. { unlock the WE record }
  484.         IgnoreBoolean(_WESetHandleLock(hWE, saveWELock));
  485.  
  486.     end;  { WECopy }
  487.  
  488. end.